package com.hedl.classroom.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hedl.classroom.base.exception.OnlinecClassroomException;
import com.hedl.classroom.base.utils.IdWorkerUtils;
import com.hedl.classroom.base.utils.QRCodeUtil;
import com.hedl.classroom.config.PayNotifyConfig;
import com.hedl.classroom.dto.AddOrderDto;
import com.hedl.classroom.dto.PayRecordDto;
import com.hedl.classroom.mapper.XcOrdersGoodsMapper;
import com.hedl.classroom.mapper.XcOrdersMapper;
import com.hedl.classroom.mapper.XcPayRecordMapper;
import com.hedl.classroom.model.po.MqMessage;
import com.hedl.classroom.po.XcOrders;
import com.hedl.classroom.po.XcOrdersGoods;
import com.hedl.classroom.po.XcPayRecord;
import com.hedl.classroom.service.MqMessageService;
import com.hedl.classroom.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author Big Watermelon
 * @description
 * @date 2023/12/18/11:11
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private XcOrdersMapper xcOrdersMapper;

    @Resource
    private XcOrdersGoodsMapper xcOrdersGoodsMapper;

    @Resource
    private XcPayRecordMapper xcPayRecordMapper;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private MqMessageService mqMessageService;

    @Value("${pay.qrcodeUrl}")
    private String qrcodeUrl;

    @Transactional
    @Override
    public PayRecordDto createOrder(String userId, AddOrderDto addOrderDto) {

        //插入订单表，订单主表，订单明细表
        XcOrders xcOrders = saveXcOrders(userId, addOrderDto);

        //插入支付记录
        XcPayRecord payRecord = createPayRecord(xcOrders);
        Long payNo = payRecord.getPayNo();

        //生成二维码
        QRCodeUtil qrCodeUtil = new QRCodeUtil();
        //支付二维码的url
        String url = String.format(qrcodeUrl, payNo);
        //二维码图片
        String qrCode = null;
        try {
            qrCode = qrCodeUtil.createQRCode(url, 200, 200);
        } catch (IOException e) {
            OnlinecClassroomException.cast("生成二维码出错！");
        }
        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(payRecord,payRecordDto);
        payRecordDto.setQrcode(qrCode);
        return payRecordDto;
    }

    /**
     * 保存支付记录
     * @param xcOrders
     * @return
     */
    private XcPayRecord createPayRecord(XcOrders xcOrders){
        //订单id
        Long orderId = xcOrders.getId();
        XcOrders orders = xcOrdersMapper.selectById(orderId);
        //如果此订单不存在就不能添加支付记录
        if (orders == null){
            OnlinecClassroomException.cast("订单不存在！");
        }

        //订单的状态
        String status = orders.getStatus();
        if ("601002".equals(status)){   //支付成功
            OnlinecClassroomException.cast("此订单已支付！");
        }

        //如果此订单支付结果为成功，不再添加支付记录，避免重复支付
        //添加支付记录
        XcPayRecord xcPayRecord = new XcPayRecord();
        //雪花算法创建订单id
        long payNo = IdWorkerUtils.getInstance().nextId();
        xcPayRecord.setPayNo(payNo);
        xcPayRecord.setOrderId(orderId);
        xcPayRecord.setOrderName(xcOrders.getOrderName());
        xcPayRecord.setTotalPrice(xcOrders.getTotalPrice());
        xcPayRecord.setCurrency("CNY");
        xcPayRecord.setCreateDate(LocalDateTime.now());
        xcPayRecord.setStatus("601001"); //未支付
        xcPayRecord.setUserId(xcOrders.getUserId());
        int insert = xcPayRecordMapper.insert(xcPayRecord);
        if (insert <= 0){
            OnlinecClassroomException.cast("插入支付记录失败！");
        }
        return xcPayRecord;
    }

    /**
     * 保存订单信息
     * @param userId
     * @param addOrderDto
     * @return
     */
    @Transactional
    public XcOrders saveXcOrders(String userId,AddOrderDto addOrderDto){
        //插入订单表，订单主表，订单明细表
        //进行幂等性判断，同一个选课记录只能有一个订单
        XcOrders xcOrders = getOrderByBusinessId(addOrderDto.getOutBusinessId());
        if (xcOrders != null){
            return xcOrders;
        }

        //插入订单主表
        xcOrders = new XcOrders();
        //雪花算法生成的订单id
        long orderId = IdWorkerUtils.getInstance().nextId();
        xcOrders.setId(orderId);
        xcOrders.setTotalPrice(addOrderDto.getTotalPrice());
        xcOrders.setCreateDate(LocalDateTime.now());
        xcOrders.setStatus("600001"); //未支付
        xcOrders.setUserId(userId);
        xcOrders.setOrderType(addOrderDto.getOrderType()); //老师这里是写死了的，订单类型
        xcOrders.setOrderName(addOrderDto.getOrderName());
        xcOrders.setOrderDescrip(addOrderDto.getOrderDescrip());
        xcOrders.setOrderDetail(addOrderDto.getOrderDetail());
        xcOrders.setOutBusinessId(addOrderDto.getOutBusinessId()); //如果这里是选课这里就记录选课表的id
        int insert = xcOrdersMapper.insert(xcOrders);
        if (insert <= 0){
            OnlinecClassroomException.cast("添加订单失败！");
        }

        //插入订单明细表
        //将前端传入的明细json串转成list
        String orderDetail = addOrderDto.getOrderDetail();
        log.info("订单描述:{}",orderDetail);
        List<XcOrdersGoods> xcOrdersGoods = JSON.parseArray(orderDetail, XcOrdersGoods.class);
        //遍历xcOrdersGoods插入订单明细表
        xcOrdersGoods.forEach(
                goods->{
                    goods.setOrderId(orderId);
                    //插入订单明细表
                    int insert1 = xcOrdersGoodsMapper.insert(goods);
                }
        );

        return xcOrders;
    }

    @Override
    public void notifyPayResult(MqMessage mqMessage) {
        //消息内容
        String jsonString = JSON.toJSONString(mqMessage);
        //创建一个持久化消息
        Message messageObj = MessageBuilder.withBody(jsonString.getBytes(StandardCharsets.UTF_8)).setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();

        //消息id
        Long id = mqMessage.getId();

        //使用CorrelationData指定回调方法，放入全局消息id
        CorrelationData correlationData = new CorrelationData(id.toString());
        correlationData.getFuture().addCallback(result->{
            if (result.isAck()){
                //消息成功发到了交换机
                log.debug("发送消息成功：{}",jsonString);
                //将消息从数据库表mq_message删掉
                mqMessageService.completed(id);
            }else {
                //消息发送失败
                log.debug("发送消息失败：{}",jsonString);
            }
        },ex->{
            //消息异常了
            log.debug("发送消息异常：{}",jsonString);

        });
        //发消送息
        rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_EXCHANGE_FANOUT,"",messageObj,correlationData);
    }

    /**
     * 根据业务id查询订单,业务id就是选课记录中的主键
     * @param businessId
     * @return
     */
    private XcOrders getOrderByBusinessId(String businessId){
        LambdaQueryWrapper<XcOrders> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(XcOrders::getOutBusinessId,businessId);
        XcOrders xcOrders = xcOrdersMapper.selectOne(queryWrapper);
        return xcOrders;
    }
}
